package com.aizuda.easyManagerTool.service.gpt.impl;

import cn.hutool.core.util.StrUtil;
import com.aizuda.easyManagerTool.domain.dto.gpt.GPTMessageDTO;
import com.aizuda.easyManagerTool.domain.entity.gpt.GPTSettingEntity;
import com.aizuda.easyManagerTool.mapper.gpt.GPTChartMapper;
import com.aizuda.easyManagerTool.service.gpt.GPTModel;
import com.aizuda.easyManagerTool.service.gpt.GPTModelService;
import com.aizuda.easyManagerTool.service.gpt.MessageModel;
import com.aizuda.easyManagerTool.service.gpt.WebSocketStreamListener;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.plexpt.chatgpt.entity.chat.Message;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import okhttp3.HttpUrl;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import org.springframework.stereotype.Service;
import org.springframework.web.socket.WebSocketSession;

import javax.annotation.Resource;
import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import java.net.URL;
import java.nio.charset.StandardCharsets;
import java.text.SimpleDateFormat;
import java.util.*;
@Service("xfAI")
@Slf4j
public class XFAiGPTServiceImpl implements GPTModelService {

    @Resource
    GPTChartMapper gptChartMapper;
    ObjectMapper objectMapper = new ObjectMapper();

    @Override
    public void streamReply(GPTMessageDTO messageDTO, WebSocketSession webSocketSession) {
        GPTModel gptModel = GPTModelManager.get(messageDTO.getTenantId());
        GPTSettingEntity gptSettingEntity = gptModel.getGptSettingEntity();
        OkHttpClient client = new OkHttpClient.Builder().build();
        String url = gptModel.getXfUrl().replace("http://", "ws://").replace("https://", "wss://");
        Request request = new Request.Builder().url(url).build();
        // 个性化参数入口，如果是并发使用，可以在这里模拟
        // 得到 WebSocketSession，拼装回复信息内容
        MessageModel model = new MessageModel();
        model.setId(messageDTO.getId());
        List<Message> msgs = (List<Message>) messageDTO.getGcContents();
        msgs.stream().map(i -> {
            Message message = objectMapper.convertValue(i, Message.class);
            if (!message.getRole().equals("user")) {
                message.setRole("assistant");
            }
           return message;
        });
        // 转换消息对象
        XFObject xfObject = new XFObject(
                new Header(gptSettingEntity.getGsXfAppid(),UUID.randomUUID().toString().substring(0, 10)),
                new Parameter(
                        new Chart("general",0.5F,1024)
                ),
                new Payload(
                        new XfMessage(msgs)
                )
        );
        WebSocketStreamListener webSocketStreamListener = new WebSocketStreamListener(webSocketSession, xfObject, model);
        client.newWebSocket(request, webSocketStreamListener);
        webSocketStreamListener.setOnComplate(msg -> {
            if(StrUtil.isBlank(msg)){
                return;
            }
            List<Message> messages = (List<Message>) messageDTO.getGcContents();
            ArrayList<Message> arrayList = new ArrayList<>();
            arrayList.addAll(messages);
            arrayList.add(Message.builder().name("ai").role("assistant").content(msg).build());
            messageDTO.setGcContents(arrayList);
            gptChartMapper.updateById(messageDTO);
        });
    }

    @Override
    public void reply(GPTMessageDTO messageDTO, WebSocketSession webSocketSession) {

    }

    @Override
    public void connect(GPTMessageDTO messageDTO) {
        GPTModel gptModel = GPTModelManager.get(messageDTO.getTenantId());
        GPTSettingEntity gptSettingEntity = gptModel.getGptSettingEntity();
        String authUrl = null;
        try {
            authUrl = getAuthUrl(messageDTO.getModel(), gptSettingEntity.getGsXfKey(), gptSettingEntity.getGsXfSecret());
        } catch (Exception e) {
            log.error("讯飞解析URL出错,{}",e.getMessage());
        }
        gptModel.setXfUrl(authUrl);
    }


    private static String getAuthUrl(String hostUrl, String apiKey, String apiSecret) throws Exception {
        URL url = new URL(hostUrl);
        // 时间
        SimpleDateFormat format = new SimpleDateFormat("EEE, dd MMM yyyy HH:mm:ss z", Locale.US);
        format.setTimeZone(TimeZone.getTimeZone("GMT"));
        String date = format.format(new Date());
        // 拼接
        String preStr = "host: " + url.getHost() + "\n" +
                "date: " + date + "\n" +
                "GET " + url.getPath() + " HTTP/1.1";
        // SHA256加密
        Mac mac = Mac.getInstance("hmacsha256");
        SecretKeySpec spec = new SecretKeySpec(apiSecret.getBytes(StandardCharsets.UTF_8), "hmacsha256");
        mac.init(spec);
        byte[] hexDigits = mac.doFinal(preStr.getBytes(StandardCharsets.UTF_8));
        // Base64加密
        String sha = Base64.getEncoder().encodeToString(hexDigits);
        // 拼接
        String authorization = String.format("api_key=\"%s\", algorithm=\"%s\", headers=\"%s\", signature=\"%s\"", apiKey, "hmac-sha256", "host date request-line", sha);
        // 拼接地址
        HttpUrl httpUrl = Objects.requireNonNull(HttpUrl.parse("https://" + url.getHost() + url.getPath())).newBuilder().
                addQueryParameter("authorization", Base64.getEncoder().encodeToString(authorization.getBytes(StandardCharsets.UTF_8))).
                addQueryParameter("date", date).
                addQueryParameter("host", url.getHost()).
                build();
        return httpUrl.toString();
    }

    @AllArgsConstructor
    @NoArgsConstructor
    @Data
    public  static  class XFObject{
        Header header;
        Parameter parameter;
        Payload payload;
    }

    @AllArgsConstructor
    @NoArgsConstructor
    @Data
    class Header{
        String app_id;
        String uid;
    }

    @AllArgsConstructor
    @NoArgsConstructor
    @Data
    class Parameter{
        Chart chat;
    }

    @AllArgsConstructor
    @NoArgsConstructor
    @Data
    class Chart{
        String domain;
        float temperature;
        Integer max_tokens;
    }

    @AllArgsConstructor
    @NoArgsConstructor
    @Data
    class Payload{
        XfMessage message;
    }

    @AllArgsConstructor
    @NoArgsConstructor
    @Data
    class XfMessage{
        List<Message> text;
    }


}
